.. _Чтение из стандартного ввода:

Чтение из стандартного ввода
============================

Любые данные, считываемые программой, сначала должны быть сохранены в переменной.
Например, программа, считывающая количество учащихся из входных данных, должна сохранить
эту информацию в переменной. Тип этой конкретной переменной может быть int.
Как мы видели в предыдущей главе, нам не нужно вводить стандартный вывод при
печати на выходе, потому что это подразумевается. Далее,в качестве аргумента указывается то, что должно быть напечатано.
Итак, write(studentCount) достаточно для вывода
значения studentCount.
Подводя итог:

* поток: стандартная
* операция вывода: запись
* данные: значение переменной studentCount
* цель: обычно окно терминала


Обратная операция (Чтение) - readf; она считывается из стандартного ввода. Буква "f" в его
названии означает форматированный ввод, поскольку то, что он считывает, всегда должно быть представлено в
определенном формате. В предыдущей главе мы также видели, что стандартным потоком ввода является stdin.
В случае чтения по-прежнему не хватает одного фрагмента головоломки: где хранить данные.

Подводя итог:

.. index::
    stdin
    readf

* поток: stdin
* операция: readf
* данные: некоторая информация
* цель: ?


Местоположение, где хранить данные, определяется адресом переменной.
Адрес переменной - это точное местоположение в памяти компьютера, где хранится ее значение.
В D символ &, который вводится перед именем, указывает на то что имя определяет адрес того, что
представляет это имя. Например,

* адрес studentCount - это &studentCount.

Здесь &studentCount может быть прочитано как "адрес переменной studentCount" и является
недостающей информацией для замены  вопросительного знака выше:

.. index::
    read

* поток: stdin
* операция: read
* данные: некоторая информация
* цель: местоположение переменной studentCount


Ввод символа & перед именем означает указание на то, что представляет собой это имя. Этот
концепция является основой ссылок и указателей, которые мы увидим в последующих главах.
Я оставлю одну особенность использования readf на потом; пока давайте примем
за правило, что первым аргументом readf должен быть "%s".

.. code-block:: d

    readf("%s", &studentCount);


На самом деле, readf может работать и без символа &:

.. code-block:: d

    readf("%s", studentCount);


Хотя код чище и безопаснее без символа &, я продолжу использовать readf с указателями отчасти для того, чтобы подготовить вас к понятиям
ссылок (:ref:`Типы значения и ссылочные типы<глава_34_start>`)
и ссылочных параметров функций (:ref:`Параметры функций<глава_35_start>`).

"%s" указывает, что данные должны быть автоматически преобразованы способом,
подходящим для типа переменной. Например, когда символы '4' и '2'
считываются в переменную типа int, они преобразуются в целое значение 42.
Приведенная ниже программа попросит пользователя ввести количество студентов. Вы должны
нажать клавишу Enter после ввода данных:

.. code-block:: d

    import std.stdio;
    void main() {
        write("Сколько здесь студентов? ");
    /* Определение переменной, которая будет использоваться для
     * хранения информации, считываемой из входных данных. */
       int studentCount;
    // Сохраняем входные данные в этой переменной
        readf("%s", &studentCount);
        writeln("Понял: есть", studentCount, "студенты.");
    }

Пропуск пробельных символов
---------------------------

Даже клавиша Enter, которую мы нажимаем после ввода данных, сохраняется в виде специального кода
и помещается в поток stdin. Это полезно для программ, чтобы определить, была ли введена информация в одной строке или в нескольких строках.
Хотя иногда такие специальные коды полезны, в большинстве случаев они не важны для
программы и должны быть отфильтрованы из входных данных. В противном случае они блокируют
ввод и препятствуют чтению других данных.
Чтобы увидеть эту проблему в программе, давайте также прочитаем количество учителей из
входных данных:

.. code-block:: d

    import std.stdio;

    void main()
    {
        write("How many students are there? ");
        /* The definition of the variable that will be used to
         * store the information that is read from the input. */
        int studentCount;
        // Storing the input data to that variable
        readf("%s", &studentCount);
        writeln("Got it: There are ", studentCount, " students.");
    }


К сожалению, программа не может использовать этот код при ожидании значения int:

.. code-block:: console

    Сколько всего студентов? 100
    здесь генерируется исключение

Специальный код, представляющий клавишу Enter, которая была нажата при вводе предыдущих 100, все еще находится во входном потоке и блокирует его:

.. code-block:: console

    100[Код ввода]

Решение состоит в том, чтобы использовать пробел перед %s, чтобы указать, что код ввода, который появляется перед считыванием количества учителей, не важен: " %s".
Пробелы, которые находятся в строках формата, используются для чтения и игнорирования нуля или более невидимых символов, которые в противном случае отображались бы во входных данных.
Считывание со стандартного ввода символов включают фактический символ пробела, коды, представляющий ввод клавиша, символ табуляции и т.д. и называются пробельными символами.
Как правило, вы можете использовать " %s" для всех данных, которые считываются из входных данных.
Приведенная выше программа работает, как ожидалось, со следующими изменениями:

.. code-block:: d

    // ...
    readf(" %s", &studentCount);
    // ...
    readf(" %s", &teacherCount);
    // ...


Результат:
.. code-block:: console

    Сколько здесь студентов? 100
    Сколько здесь учителей? 20
    Понял: здесь 100 студентов и 20 преподавателей.

Дополнительная информация
-------------------------

Строки, начинающиеся с // полезны для одиночных строк комментариев.
Чтобы записать несколько строк в виде одного комментария, заключите строки в /\* и \*/ маркеры.
Чтобы иметь возможность комментировать даже другие комментарии, используйте /+ и +/:

.. code-block:: d

    /+
    // Одна строка комментария
    /*
    Комментарий, занимающий
    несколько строк
    */
    +/

Большая часть пробелов в исходном коде незначительна. Рекомендуется
записывать более длинные выражения в виде нескольких строк или добавлять дополнительные пробелы, чтобы сделать
код более читабельным. Тем не менее, до тех пор, пока соблюдаются синтаксические правила языка, программы могут быть написаны без каких-либо дополнительных пробелов:

.. code-block:: d

    import std.stdio;void main(){writeln("Трудно читать!");}


Может быть трудно читать исходный код с небольшим количеством пробелов.

Упражнение
----------

Вводите нечисловые символы, когда программа ожидает целочисленные значения, и обратите внимание, что программа работает некорректно.
:ref:`Решение<ответы_к_главе_7>`
